#include "TerrainDecal.h"

using namespace Ogre;

TerrainDecal::TerrainDecal(const String &name, const String &material, const Vector2 &dimensions, const Vector2 &position, SceneManager* sceneMgr, Real heightOffset, unsigned int resolution)
	: res(resolution), dim(dimensions), heightOffset(heightOffset)
{
	decal = new Ogre::ManualObject(name);

	decal->setCastShadows(false);
	decal->setDynamic(true);
	decal->setRenderQueueGroup(RENDER_QUEUE_WORLD_GEOMETRY_2);

	decal->begin(material);
		for(unsigned int i = 0; i <= res; i++)
		{
			for(unsigned int j = 0; j <= res; j++)
			{
				decal->position(Ogre::Vector3(i, 0, j));
				decal->textureCoord(i / (Real)res, j / (Real)res);
			}
		}

		for(unsigned int i = 0; i < res; i++)
		{
			for(unsigned int j = 0; j < res; j++)
			{
				decal->quad(
					i * (res + 1) + j,
					i * (res + 1) + j + 1,
					(i + 1) * (res + 1) + j + 1,
					(i + 1) * (res + 1) + j);
			}
		}
	decal->end();

	decalNode = sceneMgr->getRootSceneNode()->createChildSceneNode(name+"node");
	decalNode->attachObject(decal);

	query = sceneMgr->createRayQuery(Ray());

	moveTo(position);
}

TerrainDecal::~TerrainDecal()
{
	delete query;
	decalNode->detachAllObjects();
	decalNode->getParent()->removeChild(decalNode);
	delete decal;
}

void TerrainDecal::moveTo(const Vector2 &position)
{
	Real xBegin = position.x - (dim.x / 2);
	Real zBegin = position.y - (dim.y / 2);

	Real xWidth = dim.x / res;
	Real zWidth = dim.y / res;

	decal->beginUpdate(0);
		for(unsigned int i = 0; i <= res; i++)
		{
			for(unsigned int j = 0; j <= res; j++)
			{
				Real x = xBegin + (xWidth * i);
				Real z = zBegin + (zWidth * j);
				Real y = getHeight(x, z) + heightOffset;

				decal->position(x, y, z);
				decal->textureCoord(i / (Real)res, j / (Real)res);
			}
		}

		for(unsigned int i = 0; i < res; i++)
		{
			for(unsigned int j = 0; j < res; j++)
			{
				decal->quad(
					i * (res + 1) + j,
					i * (res + 1) + j + 1,
					(i + 1) * (res + 1) + j + 1,
					(i + 1) * (res + 1) + j);
			}
		}
	decal->end();

}

void TerrainDecal::hide()
{
	decal->setVisible(false);
}

void TerrainDecal::show()
{
	decal->setVisible(true);
}

bool TerrainDecal::isVisible() const
{
	return decal->getVisible();
}

Real TerrainDecal::getHeight(Real x, Real z)
{
	query->setRay(Ray(Vector3(x, 5000, z), Vector3::NEGATIVE_UNIT_Y));

	RaySceneQueryResult &result = query->execute();
	RaySceneQueryResult::iterator i = result.begin();

	if(i != result.end() && i->worldFragment)
		return i->worldFragment->singleIntersection.y;

	return 0;
}